/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package com.servinf.ani.validadorani.validator;

import com.servinf.ani.validadorani.utils.PropertiesReader;
import java.io.IOException;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.swing.JTextArea;
import org.geotools.data.FileDataStore; 
import org.geotools.data.simple.SimpleFeatureSource;
import org.opengis.feature.type.AttributeDescriptor;

/**
 *
 * @author David
 */
public class Validator {
    
    //TIPOS DE DATOS
    private static final String TEXT = "Texto";
    private static final String NUMERIC = "Numérico";
    
    //OBLIGATORIEDAD
    private static final String MANDATORY = "Obligatorio";
    private static final String OPTIONAL = "Opcional";
    
    
    /**
     * Método para validar la estructura del shape
     * @param store
     * @param layerName
     * @param outputTextArea
     * @return 
     */
    public static boolean validateStructure(FileDataStore store, String layerName, JTextArea outputTextArea) {
       
        outputTextArea.append("********* VALIDACIÓN DE ESTRUCTURA *********\n");
        outputTextArea.append("El shape contiene los campos : \n");
        //Se comparan los campos de shape vs los esperados(Guardados en el properties)
        try {
            Map<String, Boolean> mandatoryFields = PropertiesReader.getFieldsOfLayer(layerName);
            SimpleFeatureSource featureSource = store.getFeatureSource();  
            List<AttributeDescriptor> attributes = featureSource.getSchema().getAttributeDescriptors();
            outputTextArea.append("{");
            for(AttributeDescriptor a : attributes) {
                String foundAttribute = a.getLocalName(); //Campo encontrado en el shape
                outputTextArea.append(foundAttribute + ",");
                if(mandatoryFields.containsKey(foundAttribute)) {
                    mandatoryFields.put(foundAttribute, Boolean.TRUE);
                }
            }
            outputTextArea.append("}\n");
            if(mandatoryFields.containsValue(Boolean.FALSE)) {
                    outputTextArea.append("Se esperaban los campos:\n");
                    outputTextArea.append(mandatoryFields.keySet().toString() + "\n");
                    
                    Set<String> keys = mandatoryFields.keySet();
                    Iterator<String> itr = keys.iterator();
                    while(itr.hasNext()) {
                        String key = itr.next();
                        if(mandatoryFields.get(key) == Boolean.FALSE) {
                            outputTextArea.append("Falta el campo "+key+" \n");
                        }
                    }
                    outputTextArea.append("El shape NO tiene la estructura correcta\n");
                    return false;                    
                }else {
                    outputTextArea.append("El shape tiene la estructura correcta \n");
                    return true;
                }
        }catch(NullPointerException e) {
            outputTextArea.setText("El archivo no puede ser leido\n");
        } catch (IOException ex) {
            Logger.getLogger(Validator.class.getName()).log(Level.SEVERE, null, ex);
        }
        return false;
    }
    
    
    /**
     * Se validan los tipos de datos del shape
     * @param store
     * @param layerName
     * @param outputTextArea
     * @return 
     */
    public static boolean validateDataTypes(FileDataStore store, String layerName, JTextArea outputTextArea) {
        outputTextArea.append("********* VALIDACIÓN DE TIPOS DE DATOS *********\n");
        try {
            Map<String, String> dataTypesMap = PropertiesReader.getDataOfLayer(layerName, PropertiesReader.DATA_TYPES);
            //SimpleFeatureIterator itr = store.getFeatureSource().getFeatures().features();
            List<AttributeDescriptor> descriptors = store.getSchema().getAttributeDescriptors();
            Iterator<AttributeDescriptor> itr = descriptors.iterator();
            outputTextArea.append("Tipos de datos leídos en el .shp: \n");
            while(itr.hasNext()) {
                AttributeDescriptor attr = itr.next();
//              AttributeTypeImpl GENERACION<String>
                String typeToString = attr.getType().toString();
                String fieldName = attr.getLocalName();
                String dataType = typeToString.substring(typeToString.indexOf("<") + 1, typeToString.indexOf(">"));
                outputTextArea.append(fieldName + " --> " + dataType +" \n");
                String typeExpected = dataTypesMap.get(fieldName);
                //Si los tipos de datos están bien, se van quitando hasta que el map quede vacío
                if(typeExpected != null) {
                    if(typeExpected.equals(TEXT) && dataType.equals("String")) {
                        dataTypesMap.remove(fieldName);
                    } 
                    if(typeExpected.equals(NUMERIC) && (dataType.equals("Double") || dataType.equals("Long"))) {
                        dataTypesMap.remove(fieldName);
                    }
                }
            } 
            if(!dataTypesMap.isEmpty()) {
                outputTextArea.append("El shape contiene tipos de datos que no corresponden con lo esperado\n");
                outputTextArea.append("Se esperaba que los tipos de datos fueran\n");
                outputTextArea.append(dataTypesMap.toString() + "\n");
                return false; 
            }else {
                outputTextArea.append("El shape contiene tipos de datos que corresponden con lo esperado\n");
                return true;
            }
        } catch (IOException ex) {
            Logger.getLogger(Validator.class.getName()).log(Level.SEVERE, null, ex);
        }
        return false;
    }
    
    
    /**
     * Valida que los campos que son obligatorios efectivamente sean no nulos en el shape.
     * @param store
     * @param layerName
     * @param outputTextArea
     * @return 
     */
    public static boolean validateMandatoryFields(FileDataStore store, String layerName, JTextArea outputTextArea) {
        outputTextArea.append("********* VALIDACIÓN DE OBLIGATORIEDAD DE CAMPOS *********\n");
        try {
            Map<String, String> mandatoryMap = PropertiesReader.getDataOfLayer(layerName, PropertiesReader.MANDATORY_FIELDS);
            //SimpleFeatureIterator itr = store.getFeatureSource().getFeatures().features();
            List<AttributeDescriptor> descriptors = store.getSchema().getAttributeDescriptors();
            Iterator<AttributeDescriptor> itr = descriptors.iterator();
            outputTextArea.append("Obligatoriedad leída en el .shp: \n");
            while(itr.hasNext()) {
                AttributeDescriptor attr = itr.next();
//              AttributeTypeImpl GENERACION<String>
                boolean mandatoryShape = attr.isNillable();
                String fieldName = attr.getLocalName();
                outputTextArea.append(fieldName + " --> " + mandatoryShape +" \n");
                String typeExpected = mandatoryMap.get(fieldName);
                //Si los tipos de datos están bien, se van quitando hasta que el map quede vacío
                if(typeExpected != null) {
                    if(typeExpected.equals(MANDATORY) && !mandatoryShape) {
                        mandatoryMap.remove(fieldName);
                    } 
                    if(typeExpected.equals(OPTIONAL) && mandatoryShape) {
                        mandatoryMap.remove(fieldName);
                    }
                }
            } 
            if(!mandatoryMap.isEmpty()) {
                outputTextArea.append("Los siguientes campos no corresponden con la obligatoriedad esperada.\n");
                outputTextArea.append(mandatoryMap.toString() + "\n");
                return false;
            }else {
                outputTextArea.append("Los campos en el shape corresponden con la obligatoriedad esperada\n");
                return true;
            }
        } catch (IOException ex) {
            Logger.getLogger(Validator.class.getName()).log(Level.SEVERE, null, ex);
        }
        return false;
    }
            
    
    
    
    
}
